/********************************Copyright I&S Team*****************************
 * ＊ 文件名：	memory.c
 * ＊ 描述	：	内存操作实现原码
 * ＊ 创建者：	UnartyChen
 * ＊ 版本	：	V1.0
 * ＊ 日期	：	2015.03.12
 * ＊ 修改	：	2017.03.17 Unarty
                更新字节对齐方法 line = 50. 移除内存起始边界判断， 
                修改内存标记方法，MEMORY_FLAG^areaSize
                2017.09.05 Unarty
                更新分配Bug, 当可分配区域 n - size < sizeof(MemArea_t) 时, 会出现下下结点内存值复盖
                修改分配内存标记方法。
                2019.03.26 Unarty
                内存释放增加地址边界对齐判断，某些设备内存非对齐访问时会导致硬件异常。
                2019.06.25 增加内存空间查看功能
                2020.11.18 去除前指针做为Size有效值的标记方法。增加中断全局控制开关，
                防止释放内存的时候因中断中内存申请导致异常内存访问。
                2022.03.04 回退至使用前指针做为内存Size有效值判断方法，防止内存重复释放，当最后一个空数据块出现
                重复释放时导致内存释放进入死循环
                2022.07.27 内存申请增加中断关闭与开启的过程，防止中断重入导致内存被重复申请使用
                2022.10.15 增加内存已使用空间与空闲空间信息打印
                2022.10.21 优什么内存标记方法，增快代码执行效率
 * ****************************************************************************/
#include "memory.h"
#include "Swap.h"
#include "Public.h"

#define MEMORY_ALIGNMENT (sizeof(mcu_t))                //内存最小边界对齐
   
typedef struct memArea
{
	struct memArea	*nextArea;
	mcu_t			areaSize;
}MemArea_t;		//内存区域块描述

static mcu_t s_user; 
static MemArea_t *mem;
static void_fun_u8p_u16 output;
static void memory_trans(void);


/*******************************************************************************
 * ＊ 函数名：	memory_init
 * ＊ 描述	：	内存申请分配空间初始化
 * ＊ 参数	：	memAddr:	动态内存分配的地址
				memSize:	动态内存分配的空间
 * ＊ 返回	：	无
 * ＊ 注意	：	无
 * ****************************************************************************/
void memory_init(void *memAddr, mcu_t memSize)
{
	mem = (MemArea_t*)memAddr;
	mem->areaSize = memSize;
	mem->nextArea = null;
    output = null;
    s_user = 0;
}

/*******************************************************************************
 * ＊ 函数名：	memory_state
 * ＊ 描述	：	内存未分配空间状态输出
 * ＊ 参数	：	fun: 状态输出接口函数
 * ＊ 返回	：	无
 * ＊ 注意	：	无
 * ****************************************************************************/
void memory_state(void_fun_u8p_u16 fun)
{
    output = fun;
}

/*******************************************************************************
 * ＊ 函数名：	memory_apply
 * ＊ 描述	：	内存申请
 * ＊ 参数	：	size:	空间大小
 * ＊ 返回	：	申请的地址，null（申请失败）／有效内存地址（申请成功)
 * ****************************************************************************/
void *memory_apply(mcu_t size)
{
    MemArea_t *tail, *pion;
    void *memAddr = null;

    /*字节对齐*/
    size += sizeof(MemArea_t) + (MEMORY_ALIGNMENT - 1);
    size &= ~(MEMORY_ALIGNMENT - 1);
    IRQ_disable();
    for (pion = (MemArea_t*)&mem, tail = mem; tail != null; pion = tail, tail = tail->nextArea)
    {
        if (tail->areaSize >= size)
        {
            
            memAddr = tail;
            if ((tail->areaSize - size) < (sizeof(MemArea_t) + MEMORY_ALIGNMENT))
            {
                pion->nextArea = tail->nextArea;
                size = tail->areaSize;
            }
            else
            {
                tail = (MemArea_t*)((u8_t*)memAddr+size);
                tail->areaSize = ((MemArea_t*)memAddr)->areaSize - size;
                tail->nextArea = ((MemArea_t*)memAddr)->nextArea;
                pion->nextArea = tail;	
                ((MemArea_t*)memAddr)->areaSize = size;
            }
            s_user += size;
            ((MemArea_t*)memAddr)->nextArea = (MemArea_t*)(~size + 1); //取反标记分配空间大小
            
            memAddr =  ((u8_t*)memAddr+sizeof(MemArea_t));
            break;
        }			
    }
    IRQ_enadble();
	return memAddr;
}
/*******************************************************************************
 * ＊ 函数名：	memory_release
 * ＊ 描述	：	内存释放
 * ＊ 参数	：	addr:	目标释放地址
 * ＊ 返回	：	无
 * ****************************************************************************/
void memory_release(void *addr)
{
    if (null != addr && (((u32_t)addr &(MEMORY_ALIGNMENT - 1)) == 0))
    {
        MemArea_t *tail, *pion;
        MemArea_t *rlsArea = (MemArea_t*)((mcu_t)addr - sizeof(MemArea_t));
        
        if ((0 != rlsArea->areaSize) && (0 == (rlsArea->areaSize + (u32_t)(rlsArea->nextArea)))) //标记的内存空间有效
        {
            IRQ_disable();
            s_user -= rlsArea->areaSize;
            /*找到插入节点*/
            for (pion = (MemArea_t*)&mem, tail = mem; (tail < rlsArea)&& (tail != null); 
                            pion = tail, tail = tail->nextArea)
            {}	
            
            rlsArea->nextArea = tail;
            pion->nextArea = rlsArea;
            if (pion != (MemArea_t*)&mem)//目标不处于头节点
            {
                rlsArea = pion;
            }
            while (rlsArea != null &&  rlsArea < tail)
            {
                if (((u8_t*)(rlsArea) + rlsArea->areaSize) == (u8_t*)rlsArea->nextArea)	
                {
                    rlsArea->areaSize += rlsArea->nextArea->areaSize;
                    rlsArea->nextArea = rlsArea->nextArea->nextArea;
                }
                else
                {
                    rlsArea = rlsArea->nextArea;
                }
            }
            memory_trans();
            IRQ_enadble();
        }
       
    }
}

/*******************************************************************************
 * ＊ 函数名：	memory_trans
 * ＊ 描述	：	内存状态遍历
 * ＊ 参数	：	无
 * ＊ 返回	：	无
 * ＊ 注意	：	函数通过注册接口输出 , 
 * ****************************************************************************/
static void memory_trans(void)
{
    if (output != null)
    {
        MemArea_t *m = mem;
        char ch[12];
        mcu_t i, j, space = 0;
        while (m != null && (((u32_t)m &(MEMORY_ALIGNMENT - 1)) == 0))
        {
            i = (int)m;
            j = m->areaSize;
            m = m->nextArea;
            space += j;
            output((u8_t*)"addr: 0x", 8);
            Swap_headTail((u8_t*)&i, sizeof(i));
            Swap_hexChar(ch, (u8_t*)&i, sizeof(i), 0);
            output((u8_t*)ch, sizeof(i)<<1);
            output((u8_t*)", size: 0x", 10);
            Swap_headTail((u8_t*)&j, sizeof(j));
            Swap_hexChar(ch, (u8_t*)&j, sizeof(j), 0);
            output((u8_t*)ch, sizeof(j)<<1);
            output((u8_t*)"; ", 2);
        }
        i = s_user;
        output((u8_t*)"\r\nMemory user 0x", 16);
        Swap_headTail((u8_t*)&i, sizeof(i));
        Swap_hexChar(ch, (u8_t*)&i, sizeof(i), 0);
        output((u8_t*)ch, sizeof(i)<<1);
        output((u8_t*)", space 0x", 10);
        Swap_headTail((u8_t*)&space, sizeof(j));
        Swap_hexChar(ch, (u8_t*)&space, sizeof(j), 0);
        output((u8_t*)ch, sizeof(j)<<1);
        output((u8_t*)"\r\n", 2);
        output = null;
    }
}
	
/******************************************************************************/

